home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / archiver / zipvinc.zip / ZIPV.C < prev    next >
C/C++ Source or Header  |  1989-02-15  |  17KB  |  679 lines

  1. /******************************************************************************
  2.  *
  3.  *
  4.  *    ZIPV  -- SHARE compatible ZIP file list utility.
  5.  *
  6.  *
  7.  *    This code was written as a demonstration of how to read
  8.  *    the ZIP file format.  It does not attempt to support
  9.  *    ZIP files which span multiple diskettes (it is not even
  10.  *    clear to me how that would be done).  It does support
  11.  *    multiple ZIP file names on the command line and does
  12.  *    support wildcards.  Under DOS 3.0 or above all files are
  13.  *    opened in SHARE compatible mode.
  14.  *
  15.  *    The output format is patterned after (stolen from) Vern
  16.  *    Buerg's ARCV format.
  17.  *
  18.  *
  19.  *    It appears that there are two ways to extract the names
  20.  *    of files contained in a ZIP file.  One copy is kept in a
  21.  *    "local file header" which proceeds the compressed file.  The
  22.  *    other copy is kept in the "central directory".  The notes
  23.  *    that accompany PKZIP are not clear whether or not these
  24.  *    will always agree.  I chose to read the information from
  25.  *    the central directory, even though I have to read past
  26.  *    all of the local file headers to get there.
  27.  *
  28.  *    This code is placed in the public domain.  You may do whatever
  29.  *    you like with it.
  30.  *
  31.  *    Ken Brown
  32.  *
  33.  *
  34.  *
  35.  *
  36.  *    Syntax:
  37.  *
  38.  *       ZIPV file_spec1[.ZIP] [file_spec2[.ZIP] ...]
  39.  *
  40.  *
  41.  *
  42.  ******************************************************************************
  43. */
  44.  
  45. #include <stdio.h>
  46. #include <stdlib.h>
  47. #include <string.h>
  48. #include <malloc.h>
  49. #include <sys/types.h>
  50. #include <sys/stat.h>
  51. #include <bios.h>
  52. #include <dos.h>
  53. #include <io.h>
  54. #include <share.h>
  55. #include <fcntl.h>
  56.  
  57.  
  58. /* These structures must be byte aligned */
  59.  
  60. #pragma pack(1)
  61.  
  62. /* Structure of the local file header */
  63.  
  64. struct LOCAL_HEADER {
  65.    long  Signature;
  66.    int   Version;
  67.    int   BitFlag;
  68.    int   CompressionMethod;
  69.    int   FileTime;
  70.    int   FileDate;
  71.    long  CRC32;
  72.    long  CompressedSize;
  73.    long  UnCompressedSize;
  74.    int   FileNameLength;
  75.    int   ExtraFieldLength;
  76.    };
  77.  
  78. /* Structure of the central directory record */
  79. struct CENTRAL_RECORD {
  80.    long  Signature;
  81.    int   VersionMadeBy;
  82.    int   VersionNeeded;
  83.    int   BitFlag;
  84.    int   CompressionMethod;
  85.    int   FileTime;
  86.    int   FileDate;
  87.    long  CRC32;
  88.    long  CompressedSize;
  89.    long  UnCompressedSize;
  90.    int   FileNameLength;
  91.    int   ExtraFieldLength;
  92.    int   CommentFieldLength;
  93.    int   DiskStartNumber;
  94.    int   InternalAttributes;
  95.    long  ExternalAttributes;
  96.    long  LocalHeaderOffset;
  97.    };
  98.  
  99. #pragma pack()
  100.  
  101.  
  102.  
  103. /*
  104.  *    This structure will be used to build a list of files
  105.  *    from a wildcard file_spec.
  106.  *
  107. */
  108. struct FILELIST {
  109.    char              FileName[83];
  110.    struct FILELIST   *NextFile;
  111.    }
  112.  
  113.  
  114.  
  115.  
  116. /* Global variables */
  117.  
  118. struct FILELIST *FileList,
  119.                 *FilePtr;
  120.  
  121.  
  122.  
  123.  
  124. static int   TotalFiles;
  125.  
  126. static long  TotalBytes;
  127. static long  TotalUnCompressedBytes;
  128.  
  129.  
  130.  
  131. /* Function prototypes */
  132.  
  133. extern  int main(int argc,char * *argv);
  134. extern  int ProcessFile(char *ZipFileName);
  135. extern  int ListZipFile(char *ZipFileName);
  136. extern  int DisplayHeaderRecord(struct CENTRAL_RECORD CentralDirRecord,char *FileName);
  137. extern  int DisplayTotals(void );
  138. extern  char *DisplayCompressionType(int Compression);
  139. extern  char *DisplayMonthName(int Month);
  140. extern  int BuildFileList(char *FileMask);
  141.  
  142.  
  143. main(int argc, char *argv[])
  144. {
  145.    int   Counter;
  146.    char  ZipFileName[83],
  147.          *StrPtr;
  148.  
  149.    if(argc < 2) {
  150.       printf("Syntax: ZIPV file_spec1[.ZIP] [file_spec2[.ZIP] ...]\n");
  151.       exit(1);
  152.       }
  153.  
  154.    for(Counter = 1; Counter < argc; Counter++) {
  155.       if(strlen(argv[Counter]) > 82) {
  156.          printf("Syntax: ZIPV file_spec1[.ZIP] [file_spec2[.ZIP] ...]\n");
  157.          exit(1);
  158.          }
  159.  
  160.       strcpy(ZipFileName,argv[Counter]);
  161.       strupr(ZipFileName);
  162.  
  163.       /* If the .ZIP extension is missing add it. */
  164.  
  165.       if(strchr(ZipFileName,'.') == NULL) {
  166.          strcat(ZipFileName,".ZIP");
  167.          }
  168.  
  169.       ProcessFile(ZipFileName);
  170.       }
  171.  
  172.    exit(0);
  173.  
  174.  
  175. }
  176.  
  177. /* Process each command line argument (may contain a wildcard). */
  178.  
  179. ProcessFile(char *ZipFileName)
  180. {
  181.  
  182.    FileList = NULL;
  183.  
  184.    /* Build a list of file names matching the file_spec. */
  185.  
  186.    BuildFileList(ZipFileName);
  187.  
  188.    /* If FileList == NULL no matching files were found. */
  189.  
  190.    if(FileList == NULL) {
  191.       if(strchr(ZipFileName,'*') == NULL && strchr(ZipFileName,'?') == NULL) {
  192.          printf("File not found: %s\n\n",ZipFileName);
  193.          }
  194.       else {
  195.          printf("No matching files found: %s\n\n",ZipFileName);
  196.          }
  197.       }
  198.    else {
  199.       FilePtr = FileList;
  200.       while(FilePtr != NULL) {
  201.          ListZipFile(FilePtr->FileName);
  202.          FilePtr = FilePtr->NextFile;
  203.          }
  204.       }
  205.  
  206.    return 0;
  207.  
  208. }
  209.  
  210.  
  211. ListZipFile(char *ZipFileName)
  212. {
  213.    int   ZipFileHandle,
  214.          BytesRead;
  215.  
  216.    long  FileOffset;
  217.  
  218.    char  *FileName,
  219.          *ReadPtr;
  220.  
  221.    struct LOCAL_HEADER LocalFileHeader;
  222.  
  223.    struct CENTRAL_RECORD CentralDirRecord;
  224.  
  225.  
  226.    /* Open the ZIP file.  Use sopen() if possible. */
  227.  
  228.    if(_osmajor >= 3) {
  229.       ZipFileHandle = sopen(ZipFileName,O_RDONLY|O_BINARY,SH_DENYWR);
  230.  
  231.       if(ZipFileHandle == -1) {
  232.          printf("File is currently locked, cannot open: %s\n\n",ZipFileName);
  233.          return 0;
  234.          }
  235.       }
  236.    else {
  237.       ZipFileHandle = open(ZipFileName,O_RDONLY|O_BINARY);
  238.  
  239.       if(ZipFileHandle == -1) {
  240.          printf("Cannot open: %s\n\n",ZipFileName);
  241.          return 0;
  242.          }
  243.       }
  244.  
  245.  
  246.  
  247.    printf("ZIP File: %s\n",ZipFileName);
  248.    printf("\n");
  249.  
  250.    TotalFiles = 0;
  251.    TotalBytes = 0L;
  252.    TotalUnCompressedBytes = 0L;
  253.  
  254.    printf("Name          Length    Stowage    SF   Size now  Date       Time    CRC \n");
  255.    printf("============  ========  ========  ====  ========  =========  ======  ========\n");
  256.  
  257.  
  258.    /* Read the signature from the first local header */
  259.  
  260.    BytesRead = read(ZipFileHandle,(char *)&LocalFileHeader,sizeof(long));
  261.  
  262.    if(BytesRead != sizeof(long)) {
  263.       printf("Not a ZIP file\n\n");
  264.       close(ZipFileHandle);
  265.       return 0;
  266.       }
  267.    if(LocalFileHeader.Signature != 0x04034b50) {
  268.       printf("Not a ZIP file\n\n");
  269.       close(ZipFileHandle);
  270.       return 0;
  271.       }
  272.  
  273.    /* Skip over all of the compressed files and get to the central
  274.       directory */
  275.  
  276.    while(1) {
  277.  
  278.       ReadPtr = (char *)&LocalFileHeader;
  279.       ReadPtr += 4;
  280.  
  281.       /* Read the remainder of the local file header (we already read
  282.          the signature. */
  283.  
  284.       BytesRead = read(ZipFileHandle,ReadPtr,sizeof(struct LOCAL_HEADER)-4);
  285.  
  286.       if(BytesRead != sizeof(struct LOCAL_HEADER) - 4) {
  287.          printf("Invalid ZIP file format\n\n");
  288.          close(ZipFileHandle);
  289.          return 0;
  290.          }
  291.  
  292.       FileOffset = LocalFileHeader.FileNameLength +
  293.                    LocalFileHeader.ExtraFieldLength +
  294.                    LocalFileHeader.CompressedSize;
  295.  
  296.       /* Jump to the next local file header */
  297.  
  298.       if(lseek(ZipFileHandle,FileOffset,SEEK_CUR) == -1) {
  299.          printf("Invalid ZIP file format\n\n");
  300.          close(ZipFileHandle);
  301.          return 0;
  302.          }
  303.  
  304.       /* Read the next signature */
  305.  
  306.       BytesRead = read(ZipFileHandle,(char *)&LocalFileHeader,sizeof(long));
  307.       if(BytesRead != sizeof(long)) {
  308.          printf("Invalid ZIP file format\n\n");
  309.          close(ZipFileHandle);
  310.          return 0;
  311.          }
  312.  
  313.       /* If we get a match we have found the beginning of the central
  314.          directory. */
  315.  
  316.       if(LocalFileHeader.Signature == 0x02014b50) {
  317.          break;
  318.          }
  319.  
  320.       }
  321.  
  322.  
  323.    CentralDirRecord.Signature = LocalFileHeader.Signature;
  324.  
  325.    /* Read the records in the central directory one at a time */
  326.    
  327.    while(1) {
  328.  
  329.       /* Read the remainder of the file header record (we already
  330.          have the signature.  ReadPtr points into CentralDirRecord
  331.          4 bytes from the beginning (right behind the signature. */
  332.  
  333.       ReadPtr = (char *)&CentralDir